package com.carleasoft.mps.cms.business.leave.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carleasoft.mps.cms.business.leave.bean.entity.LeaveEntity;
import com.carleasoft.mps.cms.business.leave.bean.entity.LeaveReportUserEntity;
import com.carleasoft.mps.cms.business.leave.bean.entity.ReportEntity;
import com.carleasoft.mps.cms.business.leave.bean.po.LeavePo;
import com.carleasoft.mps.cms.business.leave.bean.po.LeaveUserPo;
import com.carleasoft.mps.cms.business.leave.bean.po.YearCountPo;
import com.carleasoft.mps.cms.business.leave.bean.vo.LeaveTypeCountVo;
import com.carleasoft.mps.cms.business.leave.bean.vo.UserListVo;
import com.carleasoft.mps.cms.business.leave.bean.vo.YearCountVo;
import com.carleasoft.mps.cms.business.leave.dao.LeaveMapper;
import com.carleasoft.mps.cms.business.leave.service.LeaveReportUserService;
import com.carleasoft.mps.cms.business.leave.service.LeaveService;
import com.carleasoft.mps.cms.business.leave.service.ReportService;
import com.carleasoft.mps.cms.business.process.bean.entity.BaseProcessModuleEntity;
import com.carleasoft.mps.core.user.ThreadUserContext;
import com.carleasoft.mps.core.user.UserCacheData;
import com.carleasoft.mps.core.utils.IBeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: yangHao
 * @createDate:2023/6/3
 * @description:
 */
@Service
public class LeaveServiceImpl extends ServiceImpl<LeaveMapper, LeaveEntity> implements LeaveService {

    @Autowired
    private LeaveReportUserService leaveReportUserService;
    @Autowired
    private ReportService reportService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveLeave(LeaveUserPo leaveUserPo) {
        List<String> userList = leaveUserPo.getUserList();
        List<UserListVo> userInfos = this.getBaseMapper().userInfo(userList);
        Map<String, UserListVo> map = userInfos.stream().collect(Collectors.toMap(UserListVo::getUserCode, Function.identity()));
        List<LeaveReportUserEntity> leaveReportUserEntities = new ArrayList<>();
        for (String s : userList) {
            LeaveReportUserEntity leaveReportUserEntity = new LeaveReportUserEntity();
            leaveReportUserEntity.setUserCode(s);
            leaveReportUserEntity.setUserName(map.get(s).getUserName());
            leaveReportUserEntities.add(leaveReportUserEntity);
        }
        leaveUserPo.setLeaveReportUserEntities(leaveReportUserEntities);
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        if (StrUtil.isNotBlank(leaveUserPo.getLeaveCode())) {
            LeaveEntity entity = this.getOne(Wrappers.<LeaveEntity>lambdaQuery()
                    .eq(LeaveEntity::getLeaveCode, leaveUserPo.getLeaveCode()));
            leaveReportUserService.remove(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                    .eq(LeaveReportUserEntity::getLeaveReportCode, leaveUserPo.getLeaveCode()));
            entity.setStatus(1);
            entity.setCreateTime(LocalDateTime.now());
            entity.setCreatePersonCode(user.getUserCode());
            entity.setCreatePersonName(user.getUserName());
            entity.setUpdateTime(LocalDateTime.now());
            entity.setUpdatePersonCode(user.getUserCode());
            entity.setUpdatePersonName(user.getUserName());
            this.updateById(entity);
            for (LeaveReportUserEntity leaveReportUserEntity : leaveUserPo.getLeaveReportUserEntities()) {
                leaveReportUserEntity.setCode(IdWorker.getIdStr());
                leaveReportUserEntity.setType(1);
                leaveReportUserEntity.setLeaveReportCode(entity.getLeaveCode());
            }
            leaveReportUserService.saveBatch(leaveUserPo.getLeaveReportUserEntities());
            return entity.getLeaveCode();
        } else {
            String idStr = IdWorker.getIdStr();
            LeaveEntity leaveEntity = BeanUtil.copyProperties(leaveUserPo, LeaveEntity.class);
            leaveEntity.setLeaveCode(idStr);
            leaveEntity.setStatus(1);
            leaveEntity.setCreateTime(LocalDateTime.now());
            leaveEntity.setCreatePersonCode(user.getUserCode());
            leaveEntity.setCreatePersonName(user.getUserName());
            leaveEntity.setUpdateTime(LocalDateTime.now());
            leaveEntity.setUpdatePersonCode(user.getUserCode());
            leaveEntity.setUpdatePersonName(user.getUserName());
            this.save(leaveEntity);
            for (LeaveReportUserEntity leaveReportUserEntity : leaveUserPo.getLeaveReportUserEntities()) {
                leaveReportUserEntity.setCode(IdWorker.getIdStr());
                leaveReportUserEntity.setType(1);
                leaveReportUserEntity.setLeaveReportCode(idStr);
            }
            leaveReportUserService.saveBatch(leaveUserPo.getLeaveReportUserEntities());
            return idStr;
        }

    }

    @Override
    public Page<LeaveUserPo> pageQuery(Page page, LeavePo leavePo) {
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        leavePo.setUserCode(user.getUserCode());
        Page<LeaveUserPo> leaveUserPoPage = this.getBaseMapper().pageQuery(page, leavePo);
        return leaveUserPoPage;
    }

    @Override
    public boolean delete(String leaveCode) {
        boolean isOk = false;
        isOk = this.remove(Wrappers.<LeaveEntity>lambdaQuery()
                .eq(LeaveEntity::getLeaveCode, leaveCode));
        // todo 删除审批数据
        return isOk;
    }

    @Override
    public List<LeaveEntity> listLeave() {
        List<LeaveEntity> leaveEntityList = new ArrayList<>();
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        List<LeaveEntity> leaveEntities = this.list(Wrappers.<LeaveEntity>lambdaQuery()
                .eq(LeaveEntity::getStatus, 2)
                .eq(LeaveEntity::getCreatePersonCode, user.getUserCode()));
        if (CollUtil.isNotEmpty(leaveEntities)) {
            List<String> leaveCodes = leaveEntities.stream().map(LeaveEntity::getLeaveCode).collect(Collectors.toList());
            List<LeaveReportUserEntity> leaveReportUserEntities = leaveReportUserService.list(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                    .in(LeaveReportUserEntity::getLeaveReportCode, leaveCodes)
                    .eq(LeaveReportUserEntity::getType, 1));
            Map<String, List<LeaveReportUserEntity>> map = leaveReportUserEntities.stream().collect(Collectors.groupingBy(LeaveReportUserEntity::getLeaveReportCode));
            List<String> ids = new ArrayList<>();
            for (LeaveEntity leaveEntity : leaveEntities) {
                List<ReportEntity> reportEntities = reportService.list(Wrappers.<ReportEntity>lambdaQuery()
                        .eq(ReportEntity::getLeaveCode, leaveEntity.getLeaveCode())
                        .ne(ReportEntity::getStatus, 3));
                if (CollUtil.isNotEmpty(reportEntities)) {
                    List<String> reportCodes = reportEntities.stream().map(ReportEntity::getReportCode).collect(Collectors.toList());
                    List<LeaveReportUserEntity> reportUserEntities = leaveReportUserService.list(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                            .in(LeaveReportUserEntity::getLeaveReportCode, reportCodes));
                    List<String> userCodes = reportUserEntities.stream().map(LeaveReportUserEntity::getUserCode).collect(Collectors.toList());
                    if (map.containsKey(leaveEntity.getLeaveCode())) {
                        List<LeaveReportUserEntity> userEntities = map.get(leaveEntity.getLeaveCode());
                        List<String> codes = userEntities.stream().map(LeaveReportUserEntity::getUserCode).collect(Collectors.toList());
                        if (userCodes.size() != codes.size()) {
                            ids.add(leaveEntity.getLeaveCode());
                        }
                    }
                } else {
                    ids.add(leaveEntity.getLeaveCode());
                }

            }
            if (CollUtil.isNotEmpty(ids)) {
                List<LeaveEntity> entities = this.list(Wrappers.<LeaveEntity>lambdaQuery()
                        .in(LeaveEntity::getLeaveCode, ids));
                leaveEntityList.addAll(entities);
            }
        }

        return leaveEntityList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateState(LeaveEntity leaveEntity) {
        LeaveEntity entity = this.getOne(Wrappers.<LeaveEntity>lambdaQuery()
                .eq(LeaveEntity::getLeaveCode, leaveEntity.getLeaveCode()));
        entity.setStatus(leaveEntity.getStatus());
        return this.updateById(entity);
    }

    @Override
    public List<UserListVo> userList(String leaveCode) {
        List<UserListVo> userListVos = new ArrayList<>();
        List<LeaveReportUserEntity> reportUserEntities = leaveReportUserService.list(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                .eq(LeaveReportUserEntity::getLeaveReportCode, leaveCode));
        List<ReportEntity> reportEntities = reportService.list(Wrappers.<ReportEntity>lambdaQuery()
                .eq(ReportEntity::getLeaveCode, leaveCode)
                .ne(ReportEntity::getStatus, 3));
        if (CollUtil.isNotEmpty(reportEntities)) {
            List<String> reportCodes = reportEntities.stream().map(ReportEntity::getReportCode).collect(Collectors.toList());
            List<LeaveReportUserEntity> leaveReportUserEntities = leaveReportUserService.list(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                    .in(LeaveReportUserEntity::getLeaveReportCode, reportCodes));
            for (LeaveReportUserEntity reportUserEntity : reportUserEntities) {
                int aaa = 1;
                for (LeaveReportUserEntity leaveReportUserEntity : leaveReportUserEntities) {
                    if (reportUserEntity.getUserCode().equals(leaveReportUserEntity.getUserCode())) {
                        aaa = 0;
                        break;
                    }
                }
                if (aaa == 1) {
                    UserListVo userListVo = new UserListVo();
                    userListVo.setUserCode(reportUserEntity.getUserCode());
                    userListVo.setUserName(reportUserEntity.getUserName());
                    userListVos.add(userListVo);
                }
            }

        } else {
            for (LeaveReportUserEntity reportUserEntity : reportUserEntities) {
                UserListVo userListVo = new UserListVo();
                userListVo.setUserCode(reportUserEntity.getUserCode());
                userListVo.setUserName(reportUserEntity.getUserName());
                userListVos.add(userListVo);
            }
        }

        return userListVos;
    }

    @Override
    public YearCountVo yearCount(YearCountPo yearCountPo) {
        IBeanUtil.paramVerify(yearCountPo, "year");
        YearCountVo yearCountVo = new YearCountVo();
        // 月份
        List<Integer> months = new ArrayList<>();
        for (int i = 1; i < 13; i++) {
            months.add(i);
        }
        yearCountVo.setMonths(months);
        // 请假
        List<BigDecimal> leaves = new ArrayList<>();
        // 销假
        List<BigDecimal> reports = new ArrayList<>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Calendar cal = Calendar.getInstance();
        String year = yearCountPo.getYear().toString();
        cal.set(Calendar.YEAR, Integer.parseInt(year));
        cal.set(Calendar.MONTH, 0);
        for (int i = 0; i < 12; i++) {
            String[] array = new String[12];
            array[i] = sdf.format(cal.getTime());
            cal.add(Calendar.MONTH, 1);
            List<LeaveEntity> leaveEntities = this.list(Wrappers.<LeaveEntity>lambdaQuery()
                    .eq(LeaveEntity::getStatus, 2)
                    .like(LeaveEntity::getCreateTime, array[i]));
            if (CollUtil.isNotEmpty(leaveEntities)) {
                BigDecimal bigDecimal = new BigDecimal("0.00");
                for (int i1 = 0; i1 < leaveEntities.size(); i1++) {
                    LeaveEntity leaveEntity = leaveEntities.get(i1);
                    int count = leaveReportUserService.count(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                            .eq(LeaveReportUserEntity::getLeaveReportCode, leaveEntity.getLeaveCode()));
                    BigDecimal decimal = new BigDecimal(leaveEntity.getDuration());
                    BigDecimal multiply = decimal.multiply(new BigDecimal(count));
                    bigDecimal = bigDecimal.add(multiply);
                }
                leaves.add(bigDecimal);
            } else {
                leaves.add(new BigDecimal("0.00"));
            }
            List<ReportEntity> reportEntities = reportService.list(Wrappers.<ReportEntity>lambdaQuery()
                    .eq(ReportEntity::getStatus, 2)
                    .like(ReportEntity::getCreateTime, array[i]));
            if (CollUtil.isNotEmpty(reportEntities)) {
                BigDecimal reportDecimal = new BigDecimal("0.00");
                for (int i1 = 0; i1 < reportEntities.size(); i1++) {
                    ReportEntity leaveEntity = reportEntities.get(i1);
                    int count = leaveReportUserService.count(Wrappers.<LeaveReportUserEntity>lambdaQuery()
                            .eq(LeaveReportUserEntity::getLeaveReportCode, leaveEntity.getReportCode()));
                    BigDecimal decimal = new BigDecimal(leaveEntity.getDuration());
                    BigDecimal multiply = decimal.multiply(new BigDecimal(count));
                    reportDecimal = reportDecimal.add(multiply);
                }
                reports.add(reportDecimal);
            } else {
                reports.add(new BigDecimal("0.00"));
            }


        }
        yearCountVo.setLeaves(leaves);
        yearCountVo.setReports(reports);


        return yearCountVo;
    }

    @Override
    public LeaveTypeCountVo leaveTypeCount() {
        LeaveTypeCountVo leaveTypeCountVo = new LeaveTypeCountVo();
        List<LeaveEntity> leaveEntities = this.list(Wrappers.<LeaveEntity>lambdaQuery().eq(LeaveEntity::getStatus, 2));
        if (CollUtil.isNotEmpty(leaveEntities)) {
            Map<Integer, List<LeaveEntity>> map = leaveEntities.stream().collect(Collectors.groupingBy(LeaveEntity::getType));
            for (int i = 0; i < 5; i++) {
                if (map.containsKey(i + 1)) {
                    List<LeaveEntity> entities = map.get(i + 1);
                    if (i == 0) {
                        leaveTypeCountVo.setTypeOne(entities.size());
                    }
                    if (i == 1) {
                        leaveTypeCountVo.setTypeTwo(entities.size());
                    }
                    if (i == 2) {
                        leaveTypeCountVo.setTypeThree(entities.size());
                    }
                    if (i == 3) {
                        leaveTypeCountVo.setTypeFour(entities.size());
                    }
                    if (i == 4) {
                        leaveTypeCountVo.setTypeFive(entities.size());
                    }
                }
            }
        }
        return leaveTypeCountVo;
    }


}
